#include <stdlib.h>
#include <string.h>

#include <fnmatch.h>
#include <sys/types.h>
#include <regex.h>

#include <common/macro/build.h>
#include <common/datatype.h>
#include <common/predicate.h>

API_FILELOCAL int verify(void *datatype_arg, char *data, size_t size) {
	return (data[size-1] == '\0');
}

API_FILELOCAL void *predicate_generic_compile(void *datatype_arg, size_t *argsizes, char **arguments, int argc) {
	return strdup((char*)arguments[0]);
}

API_FILELOCAL void predicate_generic_release(void *predicate_arg) {
	if (predicate_arg == NULL) return;

	free(predicate_arg);
}

API_FILELOCAL void *predicate_regex_compile(void *datatype_args, size_t *argsizes, char **arguments, int argc) {
	regex_t *preg;

	preg = malloc(sizeof(*preg));
	if (regcomp(preg, (char*)arguments[0], REG_NOSUB) != 0) {
		free(preg);
		return NULL;
	}

	return preg;
}

API_FILELOCAL void predicate_regex_release(void *predicate_arg) {
	if (predicate_arg == NULL) return;

	regfree(predicate_arg);
	free(predicate_arg);
}

API_FILELOCAL int predicate_eq_execute(char *data, size_t size, void *predicate_arg, void **internal) {
	return (strncmp((char*)data, (char*)predicate_arg, size) == 0);
}

API_FILELOCAL int predicate_le_execute(char *data, size_t size, void *predicate_arg, void **internal) {
	return (strncmp((char*)data, (char*)predicate_arg, size) <= 0);
}

API_FILELOCAL int predicate_ge_execute(char *data, size_t size, void *predicate_arg, void **internal) {
	return (strncmp((char*)data, (char*)predicate_arg, size) >= 0);
}

API_FILELOCAL int predicate_lt_execute(char *data, size_t size, void *predicate_arg, void **internal) {
	return (strncmp((char*)data, (char*)predicate_arg, size) < 0);
}

API_FILELOCAL int predicate_gt_execute(char *data, size_t size, void *predicate_arg, void **internal) {
	return (strncmp((char*)data, (char*)predicate_arg, size) > 0);
}

API_FILELOCAL int predicate_glob_execute(char *data, size_t size, void *predicate_arg, void **internal) {
	return (fnmatch((char*)predicate_arg, (char*)data, size) == 0);
}

API_FILELOCAL int predicate_regex_execute(char *data, size_t size, void *predicate_arg, void **internal) {
	return (regexec((regex_t*)predicate_arg, (char*)data, 0, NULL, 0) == 0);
}

API_FILELOCAL predicate_t predicates[] = {
	{"eq", 1, 1, predicate_generic_compile, predicate_eq_execute, predicate_generic_release},
	{"le", 1, 1, predicate_generic_compile, predicate_le_execute, predicate_generic_release},
	{"ge", 1, 1, predicate_generic_compile, predicate_ge_execute, predicate_generic_release},
	{"lt", 1, 1, predicate_generic_compile, predicate_lt_execute, predicate_generic_release},
	{"gt", 1, 1, predicate_generic_compile, predicate_gt_execute, predicate_generic_release},
	{"glob", 1, 1, predicate_generic_compile, predicate_glob_execute, predicate_generic_release},
	{"regex", 1, 1, predicate_regex_compile, predicate_regex_execute, predicate_regex_release},
};

API_LIBLOCAL datatype_t dt_string = {
	"string",

	-1, -1,
	NULL, NULL, /* No arguments, ergo no parsing/destruction. */

	verify,
	NULL, /* Nothing to destroy. */

	predicates,
};
